package org.oschina.helper;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;

import org.oschina.helper.topic.ITopicHelper;
import org.oschina.plugin.PluginHelper;
import org.oschina.plugin.PluginType;
import org.oschina.util.ReflectUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

@Component
public class ApplicationHelper implements ServletContextAware,ApplicationContextAware,ApplicationListener {

	private static ApplicationContext applicationContext;
	private static ServletContext servletContext;
	private static DefaultListableBeanFactory defaultListableBeanFactory;
	
	@Autowired
	private PluginHelper pluginHelper;
	@Autowired
	private ITopicHelper topicHelper;
	
	/**
	 * 删除Bean
	 * @param target
	 */
	public static void removeBean(Class target)
	{
		String names[]=defaultListableBeanFactory.getBeanNamesForType(target);
		if(names.length==0)
			return;
		
		defaultListableBeanFactory.removeBeanDefinition(names[0]);
	}
	
	/**
	 * 创建Bean
	 * @param target
	 */
	public static void createBean(Class target)
	{
		defaultListableBeanFactory.registerBeanDefinition(target.getName(), BeanDefinitionBuilder.rootBeanDefinition(target).getBeanDefinition());
	}
	
	/**
	 * 获得bean
	 * @param type
	 * @return
	 */
	public static Object getBean(Class type)
	{
		try
		{
			return applicationContext.getBean(type);
		}
		catch(BeansException e)
		{
			return null;
		}
	}
	
	/**
	 * 根据类型获得bean
	 * @param type
	 * @return
	 */
	public static <T> Map<String,T> getBeansOfType(Class<T> type)
	{
		return applicationContext.getBeansOfType(type);
	}
	
	/**
	 * 根据类型和注解返回
	 * @param <T>
	 * @param type
	 * @param annotations
	 * @return
	 */
	public static <T> Map<String,T> getBeansOfTypeAndAnnotation(Class<T> type,Class<? extends Annotation>...annotations)
	{
		Map<String, Object> classes=(Map<String, Object>) getBeansOfType(type);
		Map<String,Object> result=new HashMap<String,Object>();
		Set<String> keys=classes.keySet();
		for(String key:keys)
		{
			Class clazz=classes.get(key).getClass();
			boolean pass=true;
			for(Class annotation:annotations)
			{
				if(ReflectUtil.getAnnotationByClass(clazz, annotation)==null)
				{
					pass=false;
					break;
				}
			}
			
			if(pass)
				result.put(key, classes.get(key));
		}
		
		return (Map<String, T>) result;
	}
	
	/**
	 * 根据注解返回bean
	 * @param annotationType
	 * @return
	 */
	public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
	{
		return applicationContext.getBeansWithAnnotation(annotationType);
	}
	
	public static ApplicationContext getApplicationContext()
	{
		return applicationContext;
	}
	
	public static ServletContext getServletContext()
	{
		return servletContext;
	}
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
	{
		defaultListableBeanFactory=(DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
		this.applicationContext=applicationContext;
	}

	@Override
	public void setServletContext(ServletContext servletContext)
	{
		this.servletContext=servletContext;
		topicHelper.init();
		pluginHelper.init();
	}

	private boolean closed=false;
	@Override
	public void onApplicationEvent(ApplicationEvent event)
	{
		if((event instanceof ContextClosedEvent))
		{
			if(!closed)
			{
				pluginHelper.execute(PluginType.CLOSE);
				closed=true;
			}
		}
	}
}